package cn.gowss.judger.core;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;


public class MultiThreadStreamGobbler extends Thread {
    private static Logger logger = LoggerFactory.getLogger(MultiThreadStreamGobbler.class);
    public static int THERAD_SLEEP_TIME = 100;
    private Process process;
    private String outputFilePath;
    private String inputFilePath; 
    private Map<String, Object> result;
    private volatile boolean isStopped = false;

    /**
     * @param inputStream the InputStream to be consumed
     * @param streamType  the stream type (should be OUTPUT or ERROR)
     */
    public MultiThreadStreamGobbler(final Process process, final String inputFilePath, final String outputFilePath) {
        this.process = process;
        this.inputFilePath = inputFilePath;
        this.outputFilePath =outputFilePath;
        this.result = new HashMap<String, Object>(2);
        this.isStopped = false;
    }

    /**
     * Consumes the output from the input stream and displays the lines consumed
     * if configured to do so.
     */
    @Override
    public void run() {
    	long timeMillis = System.currentTimeMillis();
    	Runtime run = Runtime.getRuntime();
    	run.gc();
    	// 获取开始时内存使用量
    	long startMem = run.totalMemory()-run.freeMemory();
    	OutputStream pOut = null;
        InputStream pIn = null;
    	try {
    		if(StringUtils.isEmpty(this.inputFilePath)) {
    			this.process.getOutputStream().close();
            }else {
            	pOut = this.process.getOutputStream();
            	File file = new File(inputFilePath);
            	FileUtils.copyFile(file, pOut);
            	pOut.close();
            }
    		
    		if(StringUtils.isEmpty(this.outputFilePath)) {
    			this.process.getInputStream().close();
    		}else {
    			pIn = this.process.getInputStream();
    			File writeName = new File(this.outputFilePath); // 相对路径，如果没有则要建立一个新的output.txt文件
    			writeName.createNewFile();// 创建新文件,有同名的文件的话直接覆盖
    			Thread.sleep(THERAD_SLEEP_TIME);
    			int read = pIn.read();
    			int count = 0;
    			count = pIn.available();
    			if(count > 0) {
    				byte[] buffer = new byte[count];
    				buffer[0] = (byte) read;
    				IOUtils.read(pIn, buffer, 1, count-1);
    				FileUtils.writeByteArrayToFile(writeName, buffer);
    			}
    		}
    		// 获取结束时内存使用量
    		long endMem = run.totalMemory()-run.freeMemory();
            long usedTime = System.currentTimeMillis() - timeMillis - THERAD_SLEEP_TIME;
            this.result.put("usedTime", Long.valueOf(usedTime).intValue());
            this.result.put("usedMemory", Long.valueOf((endMem-startMem)/1024).intValue());
		} catch (IOException | InterruptedException e) {
			String errorMessage = "The process [" + this.outputFilePath + "] execute failed.";
			logger.error(errorMessage, e);
			this.result.put("usedTime", 0);
            this.result.put("usedMemory", 0);
		}finally {
			this.isStopped = true;
            synchronized (this) {
                notify();
            }
        	try {
        		if(pIn != null) {
        			pIn.close();
        		}
        		if(pOut != null) {
        			pOut.close();
        		}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
    }

    public Map<String, Object> getContent() {
        if (!this.isStopped) {
            synchronized (this) {
                try {
                    wait();
                } catch (InterruptedException ignore) {
                    ignore.printStackTrace();
                }
            }
        }
        return this.result;
    }
    
}
